﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using PSE.Framework.Common;

namespace PSE.Framework.Threading
{
    public class SyncTimer : IDisposable
    {
        private Timer _timer = null;
        private bool _disposed = false;

        public SyncTimer()
            : this(TimeSpan.FromMilliseconds(-1))
        {
        }

        public SyncTimer(TimeSpan interval)
            : this(interval, true)
        {
        }

        public SyncTimer(TimeSpan interval, bool autoReset)
        {
            this.Enabled = false;
            this.Interval = interval;
            this.AutoReset = autoReset;

            // Timer vai ser disparado somente uma vez
            _timer = new Timer(new TimerCallback(TimerElapsed), null, TimeSpan.FromMilliseconds(-1), TimeSpan.FromMilliseconds(-1));
        }

        public bool Enabled { get; private set; }
        public TimeSpan Interval { get; set; }
        public bool AutoReset { get; set; }

        public void Start()
        {
            if (_disposed)
                throw new ObjectDisposedException("SyncTimer");

            if (!this.Enabled)
            {
                this.Enabled = true;

                _timer.Change(this.Interval, TimeSpan.FromMilliseconds(-1));
            }
        }

        public void Stop()
        {
            if (_disposed)
                throw new ObjectDisposedException("SyncTimer");

            if (this.Enabled)
            {
                _timer.Change(TimeSpan.FromMilliseconds(-1), TimeSpan.FromMilliseconds(-1));

                this.Enabled = false;
            }
        }

        public event EventHandler Elapsed;
        public event EventHandler<ExceptionEventArgs> ElapsedException;

        private void TimerElapsed(object state)
        {
            this.Enabled = this.AutoReset;

            try
            {
                if (Elapsed != null)
                    Elapsed(this, new EventArgs());
            }
            catch (Exception ex)
            {
                bool handled = false;

                if (ElapsedException != null)
                {
                    ExceptionEventArgs e = new ExceptionEventArgs(ex);
                    ElapsedException(this, e);
                    handled = e.Handled;
                }
                
                if (!handled)
                    throw;
            }

            if (this.Enabled && this.AutoReset)
            {
                this.Enabled = false;
                this.Start();
            }
            else
            {
                this.Enabled = false;
            }
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                this.Stop();

                if (_timer != null)
                {
                    _timer.Dispose();
                    _timer = null;
                }

                _disposed = true;
            }
        }
    }
}
